#!/usr/bin/python
import os
import re
import md5
try:
	import cPickle as pickle
except:
	import pickle
import pprint

## parameters
file_location = os.path.expanduser("~/.sbtool/")
config_filename = os.path.expanduser("~/.sbtool/sbconfig.py")
python_bin = os.path.expanduser("~/.sbtool/tmp")
project_filenames = ['README.tpl', 'app.SlackBuild.tpl', 'app.info.tpl', 'slack-desc.tpl']
target_location_path = os.getcwd()

## read-only, don't change
regexp_delimiter = re.compile(r"<% ?([a-z,A-Z,_]+) ?%>")
encasing_delimiter = re.compile(r"<% ?[a-z,A-Z,_]+ ?%>")
appname_prefix = 'app'
template_suffix = '.tpl'

def set_all_parameters (parameter_dict, command_line_options):
	open_project_source_files(parameter_dict, get_template_parameters)
	print 1, "Get template parameters\n", parameter_dict
	set_parameters_with_config_filename(parameter_dict)
	print 2, "Set parameters from configuration file\n", parameter_dict
	set_parameters_from_command_line(parameter_dict, command_line_options)
	print 3, "Get data from command-line invocation\n", parameter_dict
	set_missing_parameters_from_user_input(parameter_dict)
	print 4, "Get data directly from user\n", parameter_dict

def open_project_source_files (parameter_dict, function):	
	try:
		template_path = parameter_dict["file_location"]
		file_location = parameter_dict["file_location"]
	except KeyError:
		template_path = file_location

	for filename in parameter_dict['project_filenames']:
		try:
			file = open(checkslash(template_path) + filename, 'r')
			function(parameter_dict, file, filename)
			file.close()
		except IOError:
			print "Missing template file (", filename, "). Please supply it in:", file_location
			sys.exit(-1)

def get_template_parameters(parameter_dict, file, filename):
	lines = [ regexp_delimiter.findall(line) for line in file.readlines() ]
	filtered_lines = [ line for line in lines if line != [] ]
	template_parameters = reduce(lambda x,y: x.extend(y) or x, filtered_lines)
	for p in set(template_parameters):
		try:
			if parameter_dict[p] is not None:
				print "Parameter", p, "in parameter_dict[", p, "] is set."
		except KeyError:
			parameter_dict[p] = None
	
def set_parameters_with_config_filename (parameter_dict):
	## tell interpreter where to find the sbconfig.py
	import sys
	sys.path.append(file_location)
	## stuff data into the 
	try:
		import sbconfig
	except ImportError:
		config_filename = parameter_dict['config_filename']
		if os.path.exists(config_filename) and config_filename.endswith('.py'):
			exec "import " + config_filename[:-3] + ' as sbconfig'
		else:
			print "config_filename does not exist or its filename doesn't end with '.py'!"
			sys.exit(1)
		
	for key in vars(sbconfig):
		if not key.startswith('__') and not key.endswith('__'):
			parameter_dict[key] = getattr(sbconfig,key)

def set_parameters_from_command_line (parameter_dict, command_line_options):
	for option in vars(command_line_options):
		try:
			if parameter_dict[option] is None:
				parameter_dict[option] = getattr(command_line_options, option)
		except KeyError:
			parameter_dict[option] = None

def set_missing_parameters_from_user_input (parameter_dict):
	print "Please add quotation marks, for example: \"somevalue\" or '2.1.0-rc' or '' or \"\""
	for k in parameter_dict.keys():
		if parameter_dict[k] is not None:
			continue
		if k == 'appname_length_space':
			parameter_dict[k]=" "*len(parameter_dict['appname'])
			continue
		elif k == 'datetime':
			import datetime
			now = datetime.datetime.now()
			parameter_dict[k]=now.ctime()
			continue
		loop = True
		while loop:
			try:
				message = "Please provide a value for the " + k + " parameter: "
				parameter_dict[k] = input(message)
				break
			except NameError:
				print "Please provide a value again (" , k , ")."
				#warning(key) ## doesn't work
			except SyntaxError:
				print "Please provide a value again (" , k , ")."
	
def checkslash (s):
	return s if s.endswith('/') else s + '/'
	
def write_templates(parameter_dict):
	# instantiate templates
	# write templates to fs
	# if not exist write path
	ps = parameter_dict
	where = checkslash(target_location_path) + ps['appname']
	os.makedirs(where)
	os.chdir(where)
	open_project_source_files(parameter_dict, put_values_in_template)
		
def put_values_in_template(parameter_dict, src_file, src_filename):
	ps = parameter_dict
	target_filename = src_filename.replace(appname_prefix, ps['appname'])
	target_filename = target_filename if not target_filename.endswith(template_suffix) else target_filename[:-4]
	target_file = open(checkslash(target_location_path) + checkslash(ps['appname']) + target_filename, 'w')
	new_lines = []
	for line in src_file:
		params = regexp_delimiter.findall(line)
		if len(params) != 0:
			new_lines.append(re.sub(encasing_delimiter,"%s",line) % tuple([ ps[p] for p in params ]))
		else:
			new_lines.append(line)
	target_file.writelines(new_lines)
	src_file.close()
	target_file.close()
	
def parse_args(av):
	# TODO
	# - mkdir tmp in ~/.sbtool if not existent
	# - throw error if any file in project_filenames not existent
	# - write function to create template files if not provided
	from optparse import OptionParser
	parser = OptionParser()
	# TODO - put add_options in sbconfig.py
	parser.add_option("-a", "--appname", \
		action="store", type="string", dest="appname")
	parser.add_option("-l", "--alias", \
		action="store", type="string", dest="appname_alias")
	parser.add_option("-y", "--copyright-years", \
		action="store", type="string", dest="copyright_years")
	parser.add_option("-d", "--datetime", \
		action="store", type="string", dest="datetime")
	parser.add_option("-u", "--download-url", \
		action="store", type="string", dest="download_url")
	parser.add_option("-q", "--homepage-url", \
		action="store", type="string", dest="homepage_url")
	parser.add_option("-m", "--maintainer", \
		action="store", type="string", dest="maintainer")
	parser.add_option("-e", "--maintainer-email", \
		action="store", type="string", dest="maintainer_email")
	parser.add_option("-s", "--signature", \
		action="store", type="string", dest="signature")
	parser.add_option("-r", "--template-version", \
		action="store", type="string", dest="version")
		
	# non-template parameters, config file maybe
	parser.add_option("-t", "--target-path", \
		action="store", type="string" \
		, dest="target_location_path", default=target_location_path )
	parser.add_option("-p", "--project-files", \
		action="store", type="string" \
		, dest="project_filenames", default=project_filenames)
	parser.add_option("-c", "--config-file", \
		action="store", type="string" \
		, dest="config_filename", default=config_filename)
	parser.add_option("-f", "--file-location", \
		action="store", type="string" \
		, dest="file_location", default=file_location)	
		
	# action
	# TODO - write and test code... make file into .tar.gz
	#parse.add_option('-P', "--pack", )
				
	return parser.parse_args(av)
	
def first_time():
	import os
	if os.path.exists(file_location): return
	os.makedirs(file_location)
	print "Create your own templates in this path: ", file_location
	file = open("sbconfig.py",'w')
	file.writelines(
		[
			'copyright_years = "2009-2010"\\n'
			, 'maintainer = "Bill Gates"\\n'
			, 'maintainer_email = "bill.gates@microsoft.com"\\n'
			, 'signature = "SBo"\\n'
			, '#target_location_path = "/home/packages"\\n'
		]
	)
	file.close()
	for filename in project_filenames:
		file = open(filename)
		file.close()
	sys.exit(-1)


#def md5file(filename):
    #"""Return the hex digest of a file without loading it all into memory"""
    #fh = open(filename)
    #digest = md5.new()
    #while 1:
        #buf = fh.read(4096)
        #if buf == "":
            #break
        #digest.update(buf)
    #fh.close()
    #return digest.hexdigest()

#def md5sum(files):
    #for filename in files:
        #try:
            #print "%s  %s" % (md5file(filename), filename)
        #except IOError, e:
            #print >> sys.stderr, "Error on %s: %s" % (filename, e)


def main(av):
	first_time()	

	parameter_dict = {
		'file_location' : file_location
		, 'config_filename' : config_filename
		, 'project_filenames' : project_filenames
		, 'target_location_path' : target_location_path
	}
	command_line_options = {}
	
	(command_line_options, args) = parse_args(av)
	
	set_all_parameters(parameter_dict, command_line_options)
	write_templates(parameter_dict)
	
if __name__ == '__main__':
	import sys
	main(sys.argv)
